<?php

namespace App\Http\Helpers;

class Crypter
{
    const WEIXIN_ENCRYPT_KEY = 'k_weixin';

    const DB_CACHE_ENCRYPT_IV = 'djt.qq.com/djtv2';
    const DB_CACHE_ENCRYPT_KEY = 'djt.qq.com/portal/CRYPT/RIJNDAEL';

    /**
     * 业务使用RSA(encrytionschme用pkcs1)方式，对上述参数进行PUBLIC_KEY加密，
     * 最后使用Base64对加密后二进制数据进行加密成可读字符串（这里建议由业务后台维护密钥以及生成加密串）
     * http://tapd.oa.com/aiseetest/markdown_wikis/#1010154281006929517
     * http://km.oa.com/group/27235/articles/show/308452?kmref=knowledge
     *
     * @param string $base_url
     * @param array $encrypted_params 需要加密的参数
     * @param array $non_encrypted_params 不需要加密的参数
     * @return string string
     * @throws \Exception
     */
    public static function getAuthorizedUrl($base_url, $encrypted_params, $non_encrypted_params = [])
    {
        $aisee = config('aisee');

        $appId = $aisee['app_id'];
        $pid = $aisee['pid'];
        $public_key = $aisee['public_key']; // 公钥放在同一目录下文件 public_key 中。
        $str = http_build_query($encrypted_params);
        $openssl_public_encrypt = openssl_public_encrypt($str, $encrypted, $public_key);
        if (!$openssl_public_encrypt) {
            throw new \Exception('openssl_public_encrypt failed! ');
        }
        $data = base64_encode($encrypted);
        $query_str = http_build_query(compact( 'appId', 'pid', 'data') + $non_encrypted_params);
        $url = $base_url . '?' . $query_str;
        return $url;
    }

    /**
     * 对应老框架中的：Crypt::enctypt();
     *
     * @param string $str
     *
     * @return string
     */
    public static function encryptStr($str, $key = self::DB_CACHE_ENCRYPT_KEY)
    {
        if (empty($str)) {
            return $str;
        }

        $str = $str . str_repeat("\0", 16 - strlen($str) % 16);
        $encrypt = openssl_encrypt($str, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, self::DB_CACHE_ENCRYPT_IV);
        return bin2hex($encrypt);
    }

    /**
     * 对应老框架中的：Crypt::decrypt();
     *
     * @param string $str
     *
     * @return string
     */
    public static function decryptStr($str, $key = self::DB_CACHE_ENCRYPT_KEY)
    {
        if (empty($str)) {
            return $str;
        }
        try{
            $decrypt = openssl_decrypt(hex2bin($str), 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, self::DB_CACHE_ENCRYPT_IV);
            return rtrim($decrypt, "\0");
        } catch (\Exception $e) {
            return null;
        }
    }

    /**
     * 字符串加密成数子
     *
     * @param string $str
     *
     * @author xitang
     *
     * @return string
     */
    public static function encodeStr($str)
    {
        $array = str_split($str);
        foreach ($array as $val) {
            $result[] = (ord($val) > 127 ? 1255 : 999) - ord($val);
        }

        return implode('', $result);
    }

    /**
     * 字符串解密
     *
     * @param string $str
     *
     * @author xitang
     *
     * @return string
     */
    public static function decodeStr($str)
    {
        preg_match_all('/1?\d{3}/', $str, $temp);
        foreach ($temp[0] as $val) {
            $result .= chr(($val[0] == 1 ? 1255 : 999) - $val);
        }

        return $result;
    }

    /**
     * RSA PKCS#1 public key encrypt
     *
     * @author batchen
     *
     * @param $data
     * @param $key
     *
     * @return array
     */
    public static function RSAEncrypt($data, $key)
    {
        $encryptedData = '';
        if (openssl_public_encrypt($data, $encryptedData, $key)) {
            $encryptedData = base64_encode($encryptedData);
        } else {
            return ['code' => '-1', 'message' => 'Unable to encrypt data'];
        }

        return ['code' => '0', 'data' => $encryptedData];
    }

    public static function encrypt($str, $key, $iv)
    {
        $str = $str . str_repeat("\0", 16 - strlen($str) % 16);
        $encrypt = openssl_encrypt($str, 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);

        return bin2hex($encrypt);
    }

    public static function decrypt($str, $key, $iv)
    {
        try {
            $decrypt = openssl_decrypt(hex2bin($str), 'AES-128-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
            return rtrim($decrypt, "\0");
        } catch (\Exception $e) {
            return '';
        }
    }
}
